package com.king.hessian;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import lombok.extern.slf4j.Slf4j;

/**
 * 拦截一个object的所有方法，使得在方法调用前，常量beanName， 变量methodName 被设入log4j的MDC
 */
@Slf4j
public final class RpcContextMethodInterceptor implements MethodInterceptor {

    private final Logger targetLog;

    private final String beanName;

    public RpcContextMethodInterceptor(String beanName, Object bean) {
        this.beanName = beanName;
        Class<?> targetClass = bean.getClass();
        this.targetLog = LoggerFactory.getLogger(targetClass);
    }

    @Override
    public Object invoke(MethodInvocation inv) throws Throwable {
        String methodName = inv.getMethod().getName();
        MDC.put("controller", beanName);
        MDC.put("action", methodName);
        long startTime = System.currentTimeMillis();
        try {
            logBefore(inv.getArguments());
            Object result = inv.proceed();
            logAfter(result);
            return result;
        } catch(Exception e) {
            log.error("rpc error", e);
            throw e;
        } finally {
            long endTime = System.currentTimeMillis();
            log.debug(beanName + "," + methodName + "," + getLogBeforeStr(inv.getArguments()) + ",rpc time = " + (endTime - startTime) + " ms");
            MDC.remove("action");
            MDC.remove("controller");
        }
    }

    public void logBefore(Object[] argv) {
        if (log.isDebugEnabled()) {
            log.debug(getLogBeforeStr(argv));
        }
    }
    
    public String getLogBeforeStr(Object[] argv) {

        StringBuilder buf = new StringBuilder();
        buf.append("rpc argv debug: ");
        if (argv == null) {
            buf.append("len(argv) = 0; ");
        }
        else {
            buf.append("len(argv) = ");
            buf.append(argv.length);
            buf.append("; ");
            for (int i = 0; i < argv.length; ++i) {
                buf.append("$");
                buf.append(i + 1);
                buf.append(" = ");
                if (argv[i] == null) {
                    buf.append("null");
                }
                else {
                    buf.append(argv[i]);
                }
                buf.append("; ");
            }
        }
        return buf.toString();
    
    }

    public void logAfter(Object ret) {
        if (log.isDebugEnabled()) {
            log.debug(getLogAfterStr(ret));
        }
    }
    
    public String getLogAfterStr(Object ret) {

        StringBuilder buf = new StringBuilder();
        buf.append("rpc ret debug: ");
        if (ret == null) {
            buf.append("ret = null; ");
        }
        else {
            buf.append("ret = ");
            buf.append(ret);
            buf.append("; ");
        }
        return buf.toString();
    
    }
}